function Complie(element, vm) {
    this.vm = vm;
    this.element = document.querySelector(element);
    this.fragment = null;
    this.init();
}

Complie.prototype = {
    init: function () {
        if (this.element) {
            // 将需要监控的对象, 全部截取出来
            this.fragment = this.nodeToFragment(this.element);

            // 解析元素
            this.complieElement(this.fragment);

            // 重新将解析好的元素返回到原位置
            this.element.appendChild(this.fragment);
        } else {
            console.error("元素不存在!");
        }
    },

    // 将此元素下的所有元素截取出来做为内存元素片段, 待编辑
    nodeToFragment: function (element) {
        // 创建一个空片段
        var documentFragment = document.createDocumentFragment();

        // 获取第一个节点
        var firstChild = element.firstChild;

        while (firstChild) {
            // appendChild后, 原来元素上的会消失
            documentFragment.appendChild(firstChild);
            // 再把el的第一个元素赋给变量
            firstChild = element.firstChild;
        }
        return documentFragment;
    },

    // 解析元素
    complieElement: function (element) {
        // 获取所有节点, 含空白等
        var childNodes = element.childNodes;
        var self = this;

        [].slice.call(childNodes).forEach(function (node) {
            var reg = /\{\{(.*)\}\}/;
            // 获取当前元素的值
            var textContent = node.textContent;

            if (self.isElementNode(node)) {
                // 是元素, 则解析元素
                self.complie(node);
            } else if (self.isTextNode(node) && reg.test(textContent)) {
                // 是文本节点
                // TODO exec原理还未弄清楚
                var exec = reg.exec(textContent);
                self.complieText(node, reg.exec(textContent)[1]);
            }

            // 如果此元素还有子节点, 继续解析下面的子节点
            if (node.childNodes && node.childNodes.length) {
                self.complieElement(node);
            }
        })
    },

    // 解析文本脚本
    complieText: function (node, exp) {
        var self = this;
        // 获取当前元素的文本值
        var initText = this.vm[exp];
        // 将值更新到此节点上
        this.updateText(node, initText);

        // 创建监听对象, 监听对象会调用模型(数据)的getter方法, 然后通过Dep订阅器与模型进行绑定,
        // 这样set时, 就能调用执行这里的回调函数更新此节点的文本
        new Watcher(this.vm, exp, function (value) {
            self.updateText(node, value);
        })
    },

    updateText: function (node, value) {
        node.textContent = typeof value == "undefined" ? '' : value;
    },

    isTextNode: function (node) {
        return node.nodeType == 3;
    },

    // 解析元素
    complie: function (node) {
        // 获取所有属性
        var nodeAttrs = node.attributes;
        var self = this;

        Array.prototype.forEach.call(nodeAttrs, function (attr) {
            var attrName = attr.name;

            // 判断是否是指定属性
            if (self.isDirective(attrName)) {
                var value = attr.value;
                var dir = attrName.substring(2);

                // 判断是否是事件
                if (self.isEventDirective(dir)) {
                    self.compileEvent(node, self.vm, value, dir);
                } else {
                    // 数据绑定
                    self.compileModel(node, self.vm, value, dir);
                }
            }

            node.removeAttribute(attrName);
        })
    },

    // 解析事件
    compileEvent: function (node, vm, exp, dir) {
        var eventType = dir.split(':')[1];
        var callback = vm.methods && vm.methods[exp];

        if (eventType && callback) {
            // 绑定事件 bind改变执行上下文, callback的上文为new TestVue()
            node.addEventListener(eventType, callback.bind(vm), false);
        }
    },

    // 解析数据模型绑定
    compileModel: function (node, vm, key, dir) {
        var self = this;
        var val = this.vm[key];

        // 更新input的值
        this.updateInputValue(node, val);

        // 添加监控, 更新此文本框
        new Watcher(this.vm, key, function (value, oldval) {
            self.updateInputValue(node, value, oldval);
        });

        // 添加input事件, 监听值是否改变, 改变时, 改变VM中的数据模型
        node.addEventListener('input', function (e) {
            var newValue = e.target.value;
            if (val === newValue) {
                return;
            }
            // 更新主VM中的值,
            self.vm[key] = newValue;
            //  更新此解释器的值 不是必须可删除
            // val = newValue;
        });
    },

    isDirective: function (attr) {
        return attr.indexOf('v-') == 0;
    },

    // 批判是否是事件
    isEventDirective: function (dir) {
        return dir.indexOf('on:') === 0;
    },

    isElementNode: function (node) {
        return node.nodeType == 1;
    },

    // 更新input的值
    updateInputValue: function (node, value, oldValue) {
        node.value = typeof value == 'undefined' ? '' : value;
    },
}
